#pragma once

#include "../Comm/comm.hpp"
#include "../Comm/util.hpp"
#include "../Comm/log.hpp"

namespace ns_compiler
{
    using namespace ns_util;
    using namespace ns_log;
    class compiler
    {
    public:
        compiler() {}
        ~compiler() {}

        // 输入：编译文件名
        // 输出：编译成功返回true 编译失败返回false
        static bool Compile(const std::string &code_name)
        {
            pid_t pid = fork();
            if (pid < 0)
            {
                LOG(ERROR) << "创建子进程时出现错误" << std::endl;
                return false;
            }
            else if (pid == 0)
            {
                /*--child--*/
                // 如果编译出错,需要将错误信息放到错误文件中
                umask(0);
                int _stderr = open(PathUtil::Compiler_error(code_name).c_str(), O_CREAT | O_WRONLY, 0644);
                if (_stderr < 0)
                {
                    LOG(ERROR) << "打开stderr文件失败" << std::endl;
                    exit(1);
                }
                // 将输出到标准错误的信息重定向到_stderr
                dup2(_stderr, 2);

                // 程序替换
                // 子进程执行编译指令, 完成对file_name.cpp的编译功能
                // g++ -o file_name.exe file_name.cpp -std=c++11
                execlp("g++", "g++", "-o", PathUtil::EXE(code_name).c_str(), PathUtil::SRC(code_name).c_str(),
                       "-std=c++11", "-D", "COMPILER_ONLINE", nullptr);

                LOG(ERROR) << "程序替换(g++启动失败)" << std::endl;
                exit(2);
            }
            else
            {
                /*--parent--*/
                waitpid(pid, nullptr, 0);
                // 编译是否成功,只需要看file_name.exe文件是否存在
                if (FileUtil::IsFileExict(PathUtil::EXE(code_name)))
                {
                    LOG(INFO) << PathUtil::EXE(code_name) << "形成可执行程序" << std::endl;
                    return true;
                }
            }
            LOG(ERROR) << "编译失败,没有形成可执行程序" << std::endl;
            return false;
        }
    };
} // namespace ns_compiler
